/**
 * @file common.cpp
 *
 * Copyright (C) 2023-2024. Huawei Technologies Co., Ltd. All rights reserved.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
#include "common.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>

extern bool g_isDevice;

void print_int8_binary(int8_t num) {
    for (int i = 7; i >= 0; i--) {
        printf("%d", (num >> i) & 1);
    }
    printf("\n");
}

bool ReadFile(const std::string &filePath, size_t fileSize, void *buffer, size_t bufferSize)
{
    struct stat sBuf;
    int fileStatus = stat(filePath.data(), &sBuf);
    if (fileStatus == -1) {
        ERROR_LOG("failed to get file %s", filePath.c_str());
        return false;
    }
    if (S_ISREG(sBuf.st_mode) == 0) {
        ERROR_LOG("%s is not a file, please enter a file", filePath.c_str());
        return false;
    }

    std::ifstream file;
    file.open(filePath, std::ios::binary);
    if (!file.is_open()) {
        ERROR_LOG("Open file failed. path = %s", filePath.c_str());
        return false;
    }

    std::filebuf *buf = file.rdbuf();
    size_t size = buf->pubseekoff(0, std::ios::end, std::ios::in);
    if (size == 0) {
        ERROR_LOG("file size is 0");
        file.close();
        return false;
    }
    std::cout << filePath << ", size:" << size << ", buffer size:" << bufferSize << ", fileSize:" << fileSize << std::endl;

    if (size > bufferSize) {
        ERROR_LOG("file size is larger than buffer size");
        file.close();
        return false;
    }
    buf->pubseekpos(0, std::ios::in);
    buf->sgetn(static_cast<char *>(buffer), size);

    print_int8_binary(static_cast<int8_t *>(buffer)[0]);
    print_int8_binary(static_cast<int8_t *>(buffer)[1]);

    fileSize = size;
    file.close();
    return true;
}

bool WriteFile(const std::string &filePath, const void *buffer, size_t size)
{
    if (buffer == nullptr) {
        ERROR_LOG("Write file failed. buffer is nullptr");
        return false;
    }

    int fd = open(filePath.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWRITE);
    if (fd < 0) {
        ERROR_LOG("Open file failed. path = %s", filePath.c_str());
        return false;
    }

    size_t writeSize = write(fd, buffer, size);
    (void)close(fd);
    if (writeSize != size) {
        ERROR_LOG("Write file Failed.");
        return false;
    }

    return true;
}

bool WriteFile_bf16Toft32(const std::string &filePath, const void *buffer, size_t size)
{
    if (buffer == nullptr) {
        ERROR_LOG("Write file failed. buffer is nullptr");
        return false;
    }

    const uint16_t* bfloat16Buffer = static_cast<const uint16_t*>(buffer);
    size_t numElements = size / sizeof(uint16_t);
    std::vector<uint32_t> float32Buffer(numElements);
    for (size_t i = 0; i < numElements; ++i) {
        // 将 bfloat16 转换为 float32：在 bfloat16 后面添加两个字节的 0
        float32Buffer[i] = static_cast<uint32_t>(bfloat16Buffer[i]) << 16;
    }


    int fd = open(filePath.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWRITE);
    if (fd < 0) {
        ERROR_LOG("Open file failed. path = %s", filePath.c_str());
        return false;
    }

    size_t writeSize = write(fd, float32Buffer.data(), float32Buffer.size() * sizeof(uint32_t));
    if (writeSize < 0) {
        ERROR_LOG("Write file failed. path = %s", filePath.c_str());
        close(fd);
        return false;
    }

    // 确保所有数据都已写入
    if (static_cast<size_t>(writeSize) != float32Buffer.size() * sizeof(uint32_t)) {
        ERROR_LOG("Write file failed. Only %zd bytes written out of %zu", writeSize, float32Buffer.size() * sizeof(uint32_t));
        close(fd);
        return false;
    }

    // 关闭文件
    if (close(fd) < 0) {
        ERROR_LOG("Close file failed. path = %s", filePath.c_str());
        return false;
    }

    return true;
}


